(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
// (c) 2014-2016 Don Coleman
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/* global cordova, module */
"use strict";

var stringToArrayBuffer = function(str) {
    var ret = new Uint8Array(str.length);
    for (var i = 0; i < str.length; i++) {
        ret[i] = str.charCodeAt(i);
    }
    // TODO would it be better to return Uint8Array?
    return ret.buffer;
};

var base64ToArrayBuffer = function(b64) {
    return stringToArrayBuffer(atob(b64));
};

function massageMessageNativeToJs(message) {
    if (message.CDVType == 'ArrayBuffer') {
        message = base64ToArrayBuffer(message.data);
    }
    return message;
}

// Cordova 3.6 doesn't unwrap ArrayBuffers in nested data structures
// https://github.com/apache/cordova-js/blob/94291706945c42fd47fa632ed30f5eb811080e95/src/ios/exec.js#L107-L122
function convertToNativeJS(object) {
    Object.keys(object).forEach(function (key) {
        var value = object[key];
        object[key] = massageMessageNativeToJs(value);
        if (typeof(value) === 'object') {
            convertToNativeJS(value);
        }
    });
}

module.exports = {

    scan: function (services, seconds, success, failure) {
        var successWrapper = function(peripheral) {
            convertToNativeJS(peripheral);
            success(peripheral);
        };
        cordova.exec(successWrapper, failure, 'BLE', 'scan', [services, seconds]);
    },

    startScan: function (services, success, failure) {
        var successWrapper = function(peripheral) {
            convertToNativeJS(peripheral);
            success(peripheral);
        };
        cordova.exec(successWrapper, failure, 'BLE', 'startScan', [services]);
    },

    stopScan: function (success, failure) {
        cordova.exec(success, failure, 'BLE', 'stopScan', []);
    },

    startScanWithOptions: function(services, options, success, failure) {
        var successWrapper = function(peripheral) {
            convertToNativeJS(peripheral);
            success(peripheral);
        };
        options = options || {};
        cordova.exec(successWrapper, failure, 'BLE', 'startScanWithOptions', [services, options]);
    },

    // this will probably be removed
    list: function (success, failure) {
        cordova.exec(success, failure, 'BLE', 'list', []);
    },

    connect: function (device_id, success, failure) {
        var successWrapper = function(peripheral) {
            convertToNativeJS(peripheral);
            success(peripheral);
        };
        cordova.exec(successWrapper, failure, 'BLE', 'connect', [device_id]);
    },

    disconnect: function (device_id, success, failure) {
        cordova.exec(success, failure, 'BLE', 'disconnect', [device_id]);
    },

    // characteristic value comes back as ArrayBuffer in the success callback
    read: function (device_id, service_uuid, characteristic_uuid, success, failure) {
        cordova.exec(success, failure, 'BLE', 'read', [device_id, service_uuid, characteristic_uuid]);
    },

    // RSSI value comes back as an integer
    readRSSI: function(device_id, success, failure) {
        cordova.exec(success, failure, 'BLE', 'readRSSI', [device_id]);
    },

    // value must be an ArrayBuffer
    write: function (device_id, service_uuid, characteristic_uuid, value, success, failure) {
        cordova.exec(success, failure, 'BLE', 'write', [device_id, service_uuid, characteristic_uuid, value]);
    },

    // value must be an ArrayBuffer
    writeWithoutResponse: function (device_id, service_uuid, characteristic_uuid, value, success, failure) {
        cordova.exec(success, failure, 'BLE', 'writeWithoutResponse', [device_id, service_uuid, characteristic_uuid, value]);
    },

    // value must be an ArrayBuffer
    writeCommand: function (device_id, service_uuid, characteristic_uuid, value, success, failure) {
        console.log("WARNING: writeCommand is deprecated, use writeWithoutResponse");
        cordova.exec(success, failure, 'BLE', 'writeWithoutResponse', [device_id, service_uuid, characteristic_uuid, value]);
    },

    // success callback is called on notification
    notify: function (device_id, service_uuid, characteristic_uuid, success, failure) {
        console.log("WARNING: notify is deprecated, use startNotification");
        cordova.exec(success, failure, 'BLE', 'startNotification', [device_id, service_uuid, characteristic_uuid]);
    },

    // success callback is called on notification
    startNotification: function (device_id, service_uuid, characteristic_uuid, success, failure) {
        cordova.exec(success, failure, 'BLE', 'startNotification', [device_id, service_uuid, characteristic_uuid]);
    },

    // success callback is called when the descriptor 0x2902 is written
    stopNotification: function (device_id, service_uuid, characteristic_uuid, success, failure) {
        cordova.exec(success, failure, 'BLE', 'stopNotification', [device_id, service_uuid, characteristic_uuid]);
    },

    isConnected: function (device_id, success, failure) {
        cordova.exec(success, failure, 'BLE', 'isConnected', [device_id]);
    },

    isEnabled: function (success, failure) {
        cordova.exec(success, failure, 'BLE', 'isEnabled', []);
    },

    enable: function (success, failure) {
        cordova.exec(success, failure, "BLE", "enable", []);
    },

    showBluetoothSettings: function (success, failure) {
        cordova.exec(success, failure, "BLE", "showBluetoothSettings", []);
    },

    startStateNotifications: function (success, failure) {
        cordova.exec(success, failure, "BLE", "startStateNotifications", []);
    },

    stopStateNotifications: function (success, failure) {
        cordova.exec(success, failure, "BLE", "stopStateNotifications", []);
    }

};

module.exports.withPromises = {
    scan: module.exports.scan,
    startScan: module.exports.startScan,
    startScanWithOptions: module.exports.startScanWithOptions,
    connect: module.exports.connect,
    startNotification: module.exports.startNotification,
    startStateNotifications: module.exports.startStateNotifications,

    stopScan: function() {
        return new Promise(function(resolve, reject) {
            module.exports.stopScan(resolve, reject);
        });
    },

    disconnect: function(device_id) {
        return new Promise(function(resolve, reject) {
            module.exports.disconnect(device_id, resolve, reject);
        });
    },

    read: function(device_id, service_uuid, characteristic_uuid) {
        return new Promise(function(resolve, reject) {
            module.exports.read(device_id, service_uuid, characteristic_uuid, resolve, reject);
        });
    },

    write: function(device_id, service_uuid, characteristic_uuid, value) {
        return new Promise(function(resolve, reject) {
            module.exports.write(device_id, service_uuid, characteristic_uuid, value, resolve, reject);
        });
    },

    writeWithoutResponse: function (device_id, service_uuid, characteristic_uuid, value) {
        return new Promise(function(resolve, reject) {
            module.exports.writeWithoutResponse(device_id, service_uuid, characteristic_uuid, value, resolve, reject);
        });
    },

    stopNotification: function (device_id, service_uuid, characteristic_uuid) {
        return new Promise(function(resolve, reject) {
            module.exports.stopNotification(device_id, service_uuid, characteristic_uuid, resolve, reject);
        });
    },

    isConnected: function (device_id) {
        return new Promise(function(resolve, reject) {
            module.exports.isConnected(device_id);
        });
    },

    isEnabled: function () {
        return new Promise(function(resolve, reject) {
            module.exports.isEnabled(resolve, reject);
        });
    },

    enable: function () {
        return new Promise(function(resolve, reject) {
            module.exports.enable(resolve, reject);
        });
    },

    showBluetoothSettings: function () {
        return new Promise(function(resolve, reject) {
            module.exports.showBluetoothSettings(resolve, reject);
        });
    },

    stopStateNotifications: function () {
        return new Promise(function(resolve, reject) {
            module.exports.stopStateNotifications(resolve, reject);
        });
    },

    readRSSI: function(device_id) {
        return new Promise(function(resolve, reject) {
            module.exports.readRSSI(device_id);
        });
    }
}

},{}],2:[function(require,module,exports){
/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

exports.TEMPORARY = 0;
exports.PERSISTENT = 1;

},{}],3:[function(require,module,exports){
/**
 * Created by simon on 10/27/16.
 */

var Point = require('./group/Point');
var Orientation = require('./DEFAULT').Orientation;

function Cube (device, state) {
    this.version = null;
    this.firmware = null;

    this.deviceId = device.deviceId;
    this.deviceName = device.deviceName;
    this.rssi = device.rssi;
    this.connId = device.connId;
    this.media = null;
    this.cacheMedia = null;
    this.orientation = Orientation.OBVERSE;

    if(state != null) {
        this.width = state.width;
        this.height = state.height;
        this.sideState = state.sideState;
    }

    this.rotate = 0;
    this.point = new Point(0, 0);
    this.group = [this];
    this.teamId = null;
}

module.exports = Cube;

},{"./DEFAULT":4,"./group/Point":9}],4:[function(require,module,exports){
const service = "CACA";
const control = "CAF3";
const notify = "CAF2";
const data = "CAF1";
const UUIDS = {
    SERVICE: service,
    CONTROL: control,
    NOTIFY: notify,
    DATA: data
};

module.exports.UUIDS = UUIDS;


const CONNECT_PERIOD = 15 * 1000;
const AUTOCONNECT_INTERVAL = 15 * 1000;
const ConnectConfig = {
    PERIOD: CONNECT_PERIOD,
    AUTO_INTERVAL: AUTOCONNECT_INTERVAL
}
module.exports.ConnectConfig = ConnectConfig;


const MAX_PACKET_DATA_SIZE = 19;
const MAX_CUBE_BUFFER_SIZE = 3002+494;
const MAX_BYTE_PER_FRAGEMENT = MAX_CUBE_BUFFER_SIZE-4*MAX_PACKET_DATA_SIZE;

const SEND_DADA = {
    MAX_PACKET_DATA_SIZE: MAX_PACKET_DATA_SIZE,
    MAX_CUBE_BUFFER_SIZE: MAX_CUBE_BUFFER_SIZE,
    MAX_BYTE_PER_FRAGEMENT: MAX_BYTE_PER_FRAGEMENT,
};
module.exports.SEND_DADA = SEND_DADA;


const Orientation = {
    OBVERSE: 0x02,
    REVERSE: 0x01,
    UP: 0x20,
    RIGHT: 0x04,
    DOWN: 0x10,
    LEFT: 0x08,
};
module.exports.Orientation = Orientation;


const Battery = {
    SERVICE: "180F",
    LEVEL: "2A19"
};
module.exports.Battery = Battery;

const BatteryState = {
    POWER_OFF: 0x03,
    CHARGING: 0x02
};
module.exports.BatteryState = BatteryState;
},{}],5:[function(require,module,exports){
/**
 * Created by simon on 12/5/16.
 */
const SEND_DATA = require('./DEFAULT').SEND_DADA;

const MAX_PACKET_DATA_SIZE = SEND_DATA.MAX_PACKET_DATA_SIZE;
const MAX_BYTE_PER_FRAGEMENT = SEND_DATA.MAX_BYTE_PER_FRAGEMENT;

var _Timer;
var _Fragments = [];
var _SendTimes = 1;
var _SendMap_pc = null;
var _MaxTimes = 6;
var _Interval = 30;
var _Cmd;

function getDataByPiece(fragment, piece) {
    if (piece > fragment.packetNum - 1) {
        return null;
    }

    var start = piece * MAX_PACKET_DATA_SIZE;
    var length = Math.min(MAX_PACKET_DATA_SIZE, fragment.buffer.byteLength-start);
    var sub = fragment.buffer.slice(start, start+length);
    var data = new Uint8Array(sub.byteLength + 1);
    data[0] = piece;
    data.set(new Uint8Array(sub), 1);
    return data;
}


function send() {
    var times = _SendTimes;
    for (var i=0; i<_Fragments.length; i++) {
        var fragment = _Fragments[i];
        if (_SendMap_pc) {
            times = centralSendingCount(fragment, 0).times;
        }
        var counter = 0;
        while (counter < times) {
            fragment.sendParket();
            counter ++;
        }
    }
}

function centralSendingCount(fragment, increase) {
    var central = _Cmd.getSerialCentral(fragment.getDeviceId());
    var centralID = -1;
    if (central) {
        centralID = central.getCentralInfo().centralID;
    }
    var obj = _SendMap_pc[centralID];
    if (!obj) {
        obj = {count:0, times:1};
        _SendMap_pc[centralID] = obj;
    }
    if (increase != 0) {
        if (increase > 0) {
            obj.count ++;
        } else if (increase < 0) {
            obj.count --;
        }
        obj.count = Math.max(1, obj.count);
        obj.times = Math.max(1, parseInt(_MaxTimes/obj.count));
        void 0;
    }
    return obj;
}

function updateFragment(fragment, increase) {
    if (increase > 0) {
        _Fragments.push(fragment);
    } else if (increase < 0) {
        var index = _Fragments.indexOf(fragment);
        if (index > -1) {
            _Fragments.splice(index, 1);
        }
    }
    if (_SendMap_pc) {
        centralSendingCount(fragment, increase);
    }

    if (_Fragments.length > 0) {
        if (!_SendMap_pc) {
            _SendTimes = Math.max(1, parseInt(_MaxTimes / _Fragments.length));
            void 0;
        }
        if (!_Timer) {
            _Timer = setInterval(send, _Interval);
        }
    } else {
        if (_SendMap_pc) {
            _SendMap_pc = {};
        }
        clearInterval(_Timer);
        _Timer = null;
    }
}


function DataFragment(buffer) {
    this.buffer = buffer;
    this.packetNum = Math.ceil(this.buffer.byteLength / MAX_PACKET_DATA_SIZE);

    var _devId;
    var _page;
    var _pieces;
    var _finish;

    this.sendContent = function (deviceId, pieces, finish) {
        _devId = deviceId;
        _page = 0;
        _finish = finish;

        if (pieces == null) {
            _pieces = [];
            for (var i=0; i<this.packetNum; i++) {
                _pieces.push(i);
            }
        } else {
            _pieces = pieces;
        }
        updateFragment(this, 1);
    },

        this.sendParket = function () {
            if (_page < _pieces.length) {
                var data = getDataByPiece(this, _pieces[_page]);
                if (data) {
                    _Cmd.sendData(_devId, data);
                    _page++;
                }
            } else {
                this.finish();
            }
        },

        this.finish = function () {
            updateFragment(this, -1);
            if (_finish) {
                _finish();
            }
            _finish = null;
        },

        this.getDeviceId = function () {
            return _devId;
        }
}

DataFragment.cutContentToFragments = function (buffer) {
    var fragments = [];
    var fragmentCount = buffer.byteLength / MAX_BYTE_PER_FRAGEMENT;
    for (var i = 0; i < fragmentCount; i++) {
        var start = i * MAX_BYTE_PER_FRAGEMENT;
        var length = Math.min(MAX_BYTE_PER_FRAGEMENT, buffer.byteLength-start);
        var end = start + length;
        var subBuffer = buffer.slice(start, end);
        var fragment = new DataFragment(subBuffer);
        fragments.push(fragment);
    }
    return fragments;
};

DataFragment.setSendingConfig = function (cmd, interval=30, maxTimes=6) {
    _Cmd = cmd;
    _Interval = interval;
    _MaxTimes = maxTimes;
    if (_Cmd.getSerialCentral) {
        _SendMap_pc = {};
    }
}

module.exports = DataFragment;

},{"./DEFAULT":4}],6:[function(require,module,exports){
/**
 * Created by simon on 12/5/16.
 */

var WLPImage = require('./WLPImage');

const IMAGE_TASK = 0xa6;
// const DEVICE_CONFIG = 0x04;
const CONTENT_START = 0x02;
const CONTENT_CHECK = 0x01;
const CONTENT_END = 0x03;

const REPEAT_MAX = 3;

const RESTART_DELAY = 3 * 1000;
var timeout = 2.0 * 1000;


const STEP = {
    INIT: 0,
    DATA: 1,
    CHECK: 2,
    END: 3,
}

function makeStartData(cube, image) {
    var imagePacketNum = 0;
    for (var i = 0; i < image.fragments.length; i++) {
        var fragment = image.fragments[i];
        imagePacketNum += fragment.packetNum;
    }
    return new Uint8Array([
        IMAGE_TASK & 0xFF,
        CONTENT_START & 0xFF,
        0,
        (cube.width & 0xFF - image.width) / 2,
        (cube.height & 0xFF - image.height) / 2,
        image.width,
        image.height,
        0xffff & 0xFF,
        (0xffff >> 8) & 0xFF,
        0x02,
        (imagePacketNum & 0xFF),
        (imagePacketNum >> 8) & 0xFF,
        image.colorCount & 0xFF,
        image.contentLen & 0xFF,
        (image.contentLen >> 8) & 0xFF
    ]);
}

function makeCheckData() {
    return new Uint8Array([
        IMAGE_TASK,
        CONTENT_CHECK
    ]);
}

function makeEndData() {
    return new Uint8Array([
        IMAGE_TASK,
        CONTENT_END,
        0x00,
        0x07,
        0x01
    ]);
}

function ImageTask(command, cube) {
    var _cmd = command;
    var _cube = cube;
    var _image;
    var _media;
    var _fragmentIndex;
    var _success;
    var _failure;
    var _stop;
    var _lost;
    var _timer;
    var _counter;
    var _cache;
    var _step;
    var _startTime;

    this.start = function (media, cache, startTime, success, failure) {
        if (this.isExcuting()) {
            if (_media == media) {
                _success = success;
                _cache = cache;
                _failure = failure;
                _startTime = startTime;
            } else {
                var temp = this;
                var stopCallback = function () {
                    var restart = function () {
                        temp.start(media, cache, startTime, success, failure);
                    }
                    setTimeout(restart, RESTART_DELAY);
                }
                this.stop(stopCallback);
            }
            return;
        }

        _success = success;
        _failure = failure;
        _cache = cache;
        _startTime = startTime;
        _media = media;
        _fragmentIndex = 0;
        _counter = {};
        _step = -1;
        _lost = null;

        if (cube.media && cube.media.description == media.description && !cache) {
            doSuccess();
            return;
        }

        if (cube.cacheMedia && cube.cacheMedia.description == media.description) {
            if (_cache) {
                doSuccess();
            } else {
                excuteStep(STEP.END);
            }
            return;
        }

        if (media.data && media.data.length > 0) {
            _image = new WLPImage(media.data);
            // timeout = Math.max(timeout, media.data.length);
        } else {
            _image = null;
            timeout = 0;
            doFailure(1, 'media null');
            return;
        }

        if (_image.fragments.length > 1 && cache) {
            doFailure(2, 'cache image fragments > 1');
            return;
        }
        if (_image.fragments.length > 3) {
            doFailure(2, 'image fragments > 3');
            return;
        }

        excuteStep(STEP.INIT);
    }

    this.stop = function (callback) {
        _stop = callback;
        _step = -2;
        _success = null;
        _failure = null;
        if (!this.isExcuting()) {
            doStop();
            return;
        }
        if (_step == STEP.DATA) {
            var fragment = _image.fragments[_fragmentIndex];
            if (!fragment) {
                fragment.finish();
            }
        }
    }

    this.continue = function (resp) {
        if (_step != responseStep(resp)) {
            return;
        }
        _counter[_step] = 0;
        if (resp[1]==0x12) {
            if (resp[2]==0x00) {    //init resp
                _lost = null;
                excuteStep(STEP.DATA);
            } else {
                doFailure(2, 'image invalid');
                return;
            }
        } else if (resp[1]==0x11) { // check resp
            var fragment = _image.fragments[_fragmentIndex];
            if (resp[2]==0x00) {    // without lost
                _fragmentIndex++;
                if (_fragmentIndex < _image.fragments.length) {
                    _lost = null;   // next fragment
                    excuteStep(STEP.DATA);
                } else {
                    if (_cache) {
                        doSuccess();
                    } else {
                        excuteStep(STEP.END);
                    }
                }
            } else if (resp[2]==0x03) {  //lost
                var framNum = resp[3];
                var framIndex = resp[4];
                if (!_lost) { _lost = [] };
                if (fragment) {
                    putLostPieces(fragment, framIndex, resp);
                }
                if (framNum == framIndex) {
                    if (_lost.length == 0) {
                        doFailure(1, resp);
                    } else {
                        void 0;
                        excuteStep(STEP.DATA);
                    }
                }
            } else {
                doFailure(2, 'image invalid');
                return;
            }
        } else if (resp[1]==0x13) {     //end resp
            if (resp[2]==0x00) {
                doSuccess();
            } else {
                doFailure(1, resp);
            }
        }
    }

    function excuteStep(step) {
        if (_step == -2) {
            doStop();
            return;
        }
        if (_counter[step] > REPEAT_MAX) {
            doFailure(1, _counter);
            return;
        }
        counterIn(step);

        void 0;

        _step = step;
        if (step == STEP.INIT) {
            _cmd.sendCommand(_cube.deviceId, makeStartData(_cube, _image));
        } else if (step == STEP.DATA) {
            if (_image.fragments.length > _fragmentIndex) {
                var fragment = _image.fragments[_fragmentIndex];
                var end = function () {
                    _counter[step] = 0;
                    excuteStep(STEP.CHECK);
                }
                fragment.sendContent(_cube.deviceId, _lost, end);
                _lost = [];
            } else {
                doFailure(1, 'send fragments fail');
                return;
            }
        } else if (step == STEP.CHECK) {
            _cmd.sendCommand(_cube.deviceId, makeCheckData(), null, null);
        } else if (step == STEP.END) {
            _cmd.sendCommand(_cube.deviceId, makeEndData(), null, null);
        } else {
            clearTimeout(_timer);
            return;
        }

        clearTimeout(_timer);
        if (step != 1) {
            _timer = setTimeout(function () {
                excuteStep(step);
            }, timeout);
        }
    }

    function putLostPieces(fragment, framIndex, resp) {
        var startIndex = (framIndex-1)*120;
        var length = Math.min(120, fragment.packetNum - startIndex);

        for(var i=0; i<length; i++) {
            var isSet = ((resp[5+(i>>3)]&0xFF)>>(i&0x07))&0x01;
            if(isSet != 1) {
                _lost.push(i+startIndex);
            }
        }
    }

    function counterIn(step) {
        if (!counterIn) _counter = {};
        var stepCount = _counter[step];
        stepCount = stepCount ? stepCount : 0;
        stepCount ++;
        _counter[step] = stepCount;
    }

    function responseStep(resp) {
        if (resp[1]==0x12) return STEP.INIT;
        if (resp[1]==0x11) return STEP.CHECK;
        if (resp[1]==0x13) return STEP.END;
    }

    function doSuccess() {
        doFinish();
        if (_cache) {
            _cube.cacheMedia = _media;
        } else {
            _cube.media = _media;
        }
        if (_success) {
            _success(callbackObject());
        }
    }

    function doFailure(code, message) {
        doFinish();
        code = code ? code : 1;
        message = message ? message : 'write data error';
        if (_failure) {
            var error = callbackObject();
            error.code = code;
            error.message = message;
            void 0;
            _failure(error);
        }
    }

    function doStop() {
        doFinish();
        if (_stop) {
            _stop();
        }
        _stop = null;
    }

    function doFinish() {
        clearTimeout(_timer);
        _cube.cacheMedia = null;
        _step = -1;
    }

    function callbackObject() {
        return {
            cube : _cube,
            media : _media,
            startTime : _startTime
        }
    }

    this.isExcuting = function () {
        return _step > 0;
    }

    this.getCube = function () {
        return _cube;
    }

    this.getMedia = function () {
        return _media;
    }

    this.getStartTime = function () {
        return _startTime;
    }
}

module.exports = ImageTask;

},{"./WLPImage":7}],7:[function(require,module,exports){
/**
 * Created by simon on 12/5/16.
 */


var DataFragment = require('./DataFragment');

function WLPImage(imageData) {
    var data = imageData.subarray(0, 3);
    this.fileType = String.fromCharCode.apply(null, data);

    this.headerLen = imageData[3]&0xFF;
    this.codecType = imageData[4]&0xFF + ((imageData[5]&0xFF)<<8) + 1;	//编码类型1--RLC 2--LZW

    this.width = imageData[6]&0xFF;
    this.height = imageData[7]&0xFF;
    this.colorCount = imageData[8];
    this.contentLen = (imageData[9]&0xFF) + ((imageData[10]&0xFF)<<8);
    this.bgColor = imageData[11] + (imageData[12]<<8);

    var fragmentBuffer = data.buffer.slice(this.headerLen, imageData.length);
    this.fragments = DataFragment.cutContentToFragments(fragmentBuffer);
}

module.exports = WLPImage;
},{"./DataFragment":5}],8:[function(require,module,exports){

var Point = require('./Point');

const HORIZONTAL = 0;
const VERTICAL = 1;
const LinearType = {
    HORIZONTAL: HORIZONTAL,
    VERTICAL: VERTICAL,
};
// module.exports.LinearType = LinearType;

const UP = 1;
const RIGHT = 1 << 1;
const DOWN = 1 << 2;
const LEFT = 1 << 3;
const Rotate = {
    /** “小块物理正上方”指向“Group的上边”，表示小块在Group中没有旋转，UP为默认值 */
    UP : UP,
    /** “小块物理正上方”指向“Group的右边”，表示小块在Group中旋转90度*/
    RIGHT :RIGHT,
    /** “小块物理正上方”指向“Group的下边”，表示小块在Group中旋转180度*/
    DOWN : DOWN,
    /** “小块物理正上方”指向“Group的左边”，表示小块在Group中旋转270度*/
    LEFT : LEFT,
};
// module.exports.Rotate = Rotate;



/**
 * GroupMatrix用来描述小块组的序列，有两种用途：
 * 1、自己创建一个GroupMatrix对象用于与cubeGroup做对比，判断两者是否匹配
 * 2、获取一个cubeGroup的GroupMatrix描述
 */
function GroupMatrix (medias, orientations, linearType) {
    var _medias = null;
    var _orientations = null;
    /** 把下标对应的编号存入map */
    var _nameMap = {};
    /** 以这个点的小块做标准，作用是给CubeGroup做同步，然后比较 */
    var _standardPoint = new Point(0, 0);
    if (linearType == LinearType.HORIZONTAL) {
        if (medias != null) {
            _medias = [];
            _medias[0] = medias;
        }

        if (orientations != null) {
            _orientations = [];
            _orientations[0] = orientations;
        }
    } else if (linearType == LinearType.VERTICAL) {
        if (medias != null) {
            _medias = [];
            for (var i = 0; i < medias.length; i++) {
                _medias[i][0] = medias[i];
            }
        }
        if (orientations != null) {
            _orientations = [];
            for (var i = 0; i < orientations.length; i++) {
                _orientations[i][0] = orientations[i];
            }
        }
    } else {
        _orientations = orientations;
    }

    /** 存放小块旋转值的二维数组，元素取值：Orientation类的UP、RIGHT、DOWN、LEFT */
    correctOrientations();
    generateNumberMap();

    this.optionRotatesAtPoint = function (x, y) {
        return optionRotatesAtPoint(x, y);
    }

    this.getMedias = function () {
        return _medias;
    }

    this.getOrientations = function () {
        return _orientations;
    }

    this.getStandardPoint = function() {
        return _standardPoint;
    }

    this.getNumberMap = function() {
        return _nameMap;
    }

    function correctOrientations() {
        if (_orientations == null) {
            _orientations = defaultOrientations();
        } else {
            if (_medias.length == _orientations.length) {
                for (var i = 0; i < _medias.length; i++) {
                    if (_medias[i].length != _orientations[i].length) {
                        _orientations = defaultOrientations();
                        return;
                    }
                }
            }
        }
    }

    function defaultOrientations() {
        var orientations = [];
        for (var i = 0; i < _medias.length; i++) {
            orientations[i] = [];
            for (var j = 0; j < _medias[i].length; j++) {
                orientations[i][j] = 1;
            }
        }
        return orientations;
    }


    function generateNumberMap() {
        _nameMap = {};
        var rotates = null;
        //把matrix转成map，且找出可选rotates最少的小块
        for (var r = 0; r < _medias.length; r++) {
            var rows = _medias[r];
            for (var c = 0; c < rows.length; c++) {
                var name = rows[c];
                if (name != null) {
                    var sides = optionRotatesAtPoint(c, r);
                    var point = new Point(c, r);
                    //寻找最优的标准点
                    if (rotates == null || sides.length < rotates.length) {
                        rotates = sides;
                        _standardPoint = point;
                    }
                    _nameMap[point.toString()] = name;
                }
            }
        }
    }

    function optionRotatesAtPoint(x, y) {
        var value = _orientations[y][x];
        return GroupMatrix.optionRotates(value);
    }
}


GroupMatrix.optionRotates = function (value) {
    var sides = [];
    for (var i = 0; i < 4; i++) {
        var side = value & (1 << i);
        if (side > 0) {
            sides.push(i);
        }
    }
    return sides;
};

// module.exports.GroupMatrix = GroupMatrix;

module.exports = {
    LinearType: LinearType,
    Rotate: Rotate,
    GroupMatrix: GroupMatrix
}
},{"./Point":9}],9:[function(require,module,exports){

function Point (x, y) {
    this.x = x == null ? 0 : x;
    this.y = y == null ? 0 : y;
    this.equals = function (point) {
        return this.x == point.x && this.y == point.y;
    }
    this.toString = function () {
        return "(" + this.x + "," + this.y + ")";
    }
}
module.exports = Point;

},{}],10:[function(require,module,exports){
'use strict';


module.exports = {
    combine2(n) {
        if (n == 2) {
            return [
                [0,1]
            ];
        } else if (n == 4) {
            return [
                [0,1,2,3],
                [0,2,1,3],
                [0,3,1,2],
            ];
        }
    },
};


},{}],11:[function(require,module,exports){
'use strict';

var Point = require('./Point');
var combineUtil = require('./combineUtil');
var GroupMatrix = require('./GroupMatrix').GroupMatrix;
var LinearType = require('./GroupMatrix').LinearType;
var Rotate = require('./GroupMatrix').Rotate;

var _mergeSides = [];
var _divideSides = [];

var _onMerge;
var _onDivide;
var _timer;
var _mergeTimer;


function CubeSide(cube, value) {
    this.cube = cube;
    this.value = value;
}

module.exports = {
    handleCubeSideStateChanged(cube, data) {
        var sideState = cube.sideState;
        var side = data[2];
        cube.sideState = side;
        if (!isOn()) return;

        for (var i = 0; i < 4; i++) {
            var s1 = sideState & (1 << i);
            var s2 = side & (1 << i);
            var changedValue = s2 - s1;
            if (changedValue != 0) {
                var sides = changedValue > 0 ? _mergeSides : _divideSides;
                putNewSide(sides, cube, changedValue);
                void 0;
            }
        }
        clearTimeout(_timer);
        if (_mergeSides.length >= 4) {
            executeAlgorithm();
        } else {
            _timer = setTimeout(function () {
                executeAlgorithm();
            }, 300);
        }
        /*
        var mutiMerge = true;

        if (!mutiMerge) {
            clearTimeout(_timer);
            if (_mergeSides.length == 2) {
                executeAlgorithm();
            } else {
                _timer = setTimeout(function () {
                    executeAlgorithm();
                }, 500);
            }
        } else {
            clearTimeout(_timer);
            _timer = setTimeout(function () {
                executeAlgorithm();
            }, 300);
        }
        */
    },

    registerMerge(onChanged) {
        _onMerge = onChanged;
    },

    registerDivide(onChanged) {
        _onDivide = onChanged;
    },

    compereMatrix(group, matrix) {
        var map = matrix.getNumberMap();
        if (Object.keys(map).length != group.length) return false;
        var thePoint = matrix.getStandardPoint();
        var media = map[thePoint.toString()];
        if (media == "*") {
            for (var i=0; i<group.length; i++) {
                var cube = group[i];
                if (compereMatrixAtCube(group, matrix, cube)) return true;
            }
        } else {
            var cube = getCube(group, media);
            return compereMatrixAtCube(group, matrix, cube);
        }
        return false;
    }
}

function isOn() {
    return _onMerge || _onDivide;
}

function compereMatrixAtCube(group, matrix, cube) {
    if (cube == null || cube.group != group) return false;
    var thePoint = matrix.getStandardPoint();
    var rotates;
    if (cube.media == "*") {
        rotates = GroupMatrix.optionRotates(Rotate.UP | Rotate.LEFT | Rotate.RIGHT | Rotate.DOWN);
    } else {
        rotates = matrix.optionRotatesAtPoint(thePoint.x, thePoint.y);
    }

    for (var i = 0; i < rotates.length; i++) {
        var rotate = rotates[i];
        transGroupAtCube(cube, thePoint, rotate);
        if (excuteCompareMatrix(group, matrix)) {
            return true;
        }
    }
    return false;
}

function excuteCompareMatrix(group, matrix) {
    var map = matrix.getNumberMap();
    var orientations = matrix.getOrientations();
    for (var i=0; i<group.length; i++)  {
        var cube = group[i];
        var media = map[cube.point.toString()];
        if (media == null) {
            return false;
        }
        if (media != cube.media && media != "*") {
            return false;
        }

        if (media != "*") {
            var orientation = orientations[cube.point.y][cube.point.x];
            if ((orientation & (1 << cube.rotate)) == 0) {
                return false;
            }
        }
    }

    return true;
}

function setupGroup(group) {
    for (var i=0; i<group.length; i++) {
        var cube = group[i];
        cube.group = group;
    }
}

function getCubeWithPoint(group, point) {
    for (var i=0; i<group.length; i++) {
        var cube = group[i];
        if (cube.point.equals(point)) {
            return cube;
        }
    }
    return null;
}

function getCube(group, media) {
    for (var i=0; i<group.length; i++) {
        var cube = group[i];
        if (cube.media == media) {
            return cube;
        }
    }
    return null;
}

function putNewSide(sides, cube, changedValue) {
    for (var i=0; i<sides.length; i++) {
        var cube1 = sides[i];
        if (cube == cube1) {
            if (cube1.value == -changedValue) {
                sides.splice(i, 1);
                return;
            }
            if (cube1.value == changedValue) {
                return;
            }
        }
    }
    var cs = new CubeSide(cube, changedValue);
    sides.push(cs);
}

function executeAlgorithm() {
    // if (window) {
    //     console.log('---------------before--------------');
    //     window.xm.printGroup();
    // }
    void 0;

    if (_mergeSides.length > 0) {
        clearTimeout(_mergeTimer);
        var error = tryMergeSides(_mergeSides);
        if (error == 0) {
            _mergeSides = [];
        } else {
            _mergeTimer = setTimeout(function () {
                _mergeSides = [];
            }, 200);
        }
    }
    if (_divideSides.length > 0 && _divideSides.length <= 4) {
        for (var i = 0; i < _divideSides.length; i++) {
            var side = _divideSides[i];
            var cube = tryDivideAtSide(side);
            if (cube) {
                if (_onDivide) {
                    _onDivide(cube, side.cube);
                }
            }
        }
    }
    _divideSides = [];
    // if (window) {
    //     console.log('---------------after--------------');
    //     window.xm.printGroup();
    // }
}

function tryMergeSides(sides) {
    if (sides.length%2 != 0) {
        return 30;
    }
    if (sides.length > 4) {
        return 40;
    }
    var list = combineUtil.combine2(sides.length);
    if (list == null || list.length == 0) {
        return false;
    }
    var errorCount = 0;
    var rotateCount = 0;
    var index = 0;
    for (var i = 0; i < list.length; i++) {
        var indexes = list[i];
        var result = mergeCubeSidesIndexes(indexes, false);
        if (result == null) continue;
        if (result[0] == 0 && result[1] == 0) {
            index = i;
            break;
        }
        if (i == 0) {
            errorCount = result[0];
            rotateCount = result[1];
        } else if (result[0] < errorCount && result[1] < rotateCount) {
            index = i;
        }
    }

    var indexes = list[index];
    var result = mergeCubeSidesIndexes(indexes, true);
    return result[0];
}

function mergeGroups(group1, group2) {
    var group = group1.concat(group2);
    setupGroup(group);
    return group;
}


function mergeCubeSidesIndexes(indexes, wantsChange) {
    if (_mergeSides.length != indexes.length) return null;
    var error = 0;
    var rotate = 0;
    for (var j = 0; j < indexes.length - 1; j=j+2) {
        var first = indexes[j];
        var second = indexes[j+1];
        var cs1 = _mergeSides[first];
        var cs2 = _mergeSides[second];
        error += tryMergeAtCubes(cs1, cs2);
        rotate += cs1.cube.rotate > 0 ? 1 : 0 + cs2.cube.rotate > 0 ? 1 : 0;
        if (wantsChange && error == 0) {
            mergeGroups(cs1.cube.group, cs2.cube.group);
            if (_onMerge) {
                _onMerge(cs1.cube.group,cs1.cube,cs2.cube);
            }
        }
    }
    return [error,rotate];
}

//两个小块发生碰撞，以cube1为标准，合并cube2的group
function tryMergeAtCubes(cs1, cs2) {
    var cube1 = cs1.cube;
    var side1 = cs1.value;
    var cube2 = cs2.cube;
    var side2 = cs2.value;
    if (cube1.group == cube2.group) {
        return 10;
    }
    if (cube1.teamId != cube2.teamId) {
        return 20;
    }

    var dir1 = (Math.log(side1) / Math.log(2));
    var dir2 = (Math.log(side2) / Math.log(2));

    var point2 = calculateNeighborPoint(cube1, dir1);

    //cube2相对于cube1的roate
    var rotate2;
    if ((dir2 - dir1) % 2 == 0) {
        rotate2 = adjustOrientation(dir2 - dir1 - 2);
    } else {
        rotate2 = adjustOrientation(dir2 - dir1);
    }

    //当前group尝试合并cube2的group
    transGroupAtCube(cube2,point2,rotate2);
    var errorCount = checkConflictForMerge(cube1.group, cube2.group);

    return errorCount;
}

function checkConflictForMerge(group1, group2) {
    var errorCount = 0;
    for (var i=0; i<group1.length; i++) {
        var cube1 = group1[i];
        for (var j=0; j<group2.length; j++) {
            var cube2 = group2[j];
            if (cube1.point.equals(cube2.point)) {
                errorCount ++;
            }
        }
    }
    return errorCount;
}


//算出cube的side相邻位置的坐标
function calculateNeighborPoint(cube, dir) {
    transGroupAtCube(cube, new Point(0,0), 0);
    var newPoint = new Point(cube.point.x, cube.point.y);
    if (dir == 0) {
        newPoint.y -= 1;
    } else if (dir == 1) {
        newPoint.x += 1;
    } else if (dir == 2) {
        newPoint.y += 1;
    } else if (dir == 3) {
        newPoint.x -= 1;
    };
    return newPoint;
}

function pointRotate(point, rotate) {
    var p = new Point(point.x, point.y);
    switch (rotate) {
        case 1:
            p.x = -point.y;
            p.y = point.x;
            break;
        case 2:
            p.x = -point.x;
            p.y = -point.y;
            break;
        case 3:
            p.x = point.y;
            p.y = -point.x;
            break;
    }
    return p;
}

//改变整个group的坐标系，1.把cube作为原点；2.旋转；3.设定偏移;4.同步到当前group。返回两个group冲突的point的数量errorCount，理论上errorCount是0才能合并
function transGroupAtCube(theCube, newPoint, newRotate) {
    var groupRotate = adjustOrientation(newRotate - theCube.rotate);
    var rotatePoint = pointRotate(theCube.point, groupRotate);
    var offset = new Point(newPoint.x - rotatePoint.x, newPoint.y - rotatePoint.y);

    if (theCube.point.equals(newPoint) && groupRotate == 0) return;
    var group = theCube.group;
    for (var i=0; i<group.length; i++) {
        var cube = group[i];
        cube.point = pointRotate(cube.point, groupRotate);
        cube.point.x += offset.x;
        cube.point.y += offset.y;

        cube.rotate = adjustOrientation(cube.rotate + groupRotate);
    }
}

function adjustOrientation(orientation) {
    const dirs = [0, 1, 2, 3];
    while (orientation < 0) {
        orientation += dirs.length;
    }
    while (orientation > dirs.length - 1) {
        orientation -= dirs.length;
    }
    return orientation;
}

function tryDivideAtSide(cubeSide) {
    var cube = cubeSide.cube;
    var dir = (Math.log(Math.abs(cubeSide.value)) / Math.log(2));
    var point = calculateNeighborPoint(cube, dir);
    var cube2 = getCubeWithPoint(cubeSide.cube.group, point);
    if (cube2 != null) {
        var success = tryDivideAtCubes(cubeSide.cube,cube2);
        if (success) {
            return cube2;
        }
    }
    return null;
}


function tryDivideAtCubes(cube1,  cube2) {
    if (!isNeighbor(cube1, cube2)) {
        return false;
    }
    var all = [].concat(cube1.group);
    var cubes = divideAtCubes(cube1, cube2, all);

    // window.xm.printGroup(cubes);

    var rest = all.filter(function(cube) {
        return cubes.indexOf(cube) === -1;
    });

    setupGroup(cubes);
    setupGroup(rest);

    transGroupAtCube(cube1,new Point(),0);
    transGroupAtCube(cube2,new Point(),0);
    return true;
}

function divideAtCubes(cube1, cube2, allCubes) {
    var newCubes = [];
    var cubes = [].concat(allCubes);

    var index = cubes.indexOf(cube2);
    if (index < 0) {
        return [cube1];
    }
    cubes.splice(index, 1);
    filterCubesToGroup(cube1,cubes,newCubes);
    return newCubes;
}

function isNeighbor(cube1, cube2) {
    if (cube1.group != cube2.group) return false;
    var x = Math.abs(cube1.point.x - cube2.point.x);
    var y = Math.abs(cube1.point.y - cube2.point.y);

    if (x == 0 && y == 1 || x == 1 && y == 0) {
        return true;
    }

    if (x == 0 && y == 0) {
        return true;
    }

    return false;
}

function filterCubesToGroup(cube, originalCubes, newCubes) {
    newCubes.push(cube);
    var point = cube.point;

    var index = originalCubes.indexOf(cube);
    originalCubes.splice(index, 1);

    var left = new Point(point.x - 1,point.y);
    var right = new Point(point.x + 1,point.y);
    var up = new Point(point.x,point.y - 1);
    var down = new Point(point.x,point.y + 1);

    var points = [left,right,up,down];
    for (var i=0; i<originalCubes.length; i++) {
        var oCube = originalCubes[i];
        for (var j=0; j<points.length; j++) {
            var neighborPoint = points[j];
            if (oCube.point.equals(neighborPoint) && newCubes.indexOf(oCube) < 0) {
                filterCubesToGroup(oCube,originalCubes,newCubes);
            }
        }
    }
}
},{"./GroupMatrix":8,"./Point":9,"./combineUtil":10}],12:[function(require,module,exports){
/**
 * Created by simon on 12/2/16.
 */

'use strict';

var LocalFileSystem = require('../../cordova/plugins/cordova-plugin-file/www/LocalFileSystem');

function FileManager() {
    //read file As Array Buffer
    this.readFile = function (path, success, failure) {
        var gotFS = function(fileEntry)
        {
            fileEntry.file(function(blob) {
                var reader = new FileReader();
                reader.onloadend = function(e) {
                    success(reader.result);
                }
                reader.readAsArrayBuffer(blob);
            });
        }
        window.resolveLocalFileSystemURL(path, gotFS, failure);
    }
}

module.exports = FileManager;


},{"../../cordova/plugins/cordova-plugin-file/www/LocalFileSystem":2}],13:[function(require,module,exports){
'use strict';

const UUIDS = require('../DEFAULT').UUIDS;
const ble = require('../../cordova/plugins/cordova-plugin-ble-central/www/ble');
const connectTask = require('./connectTask_mobile');
const FileManager = require('./FileManager_mobile');

module.exports = {
    //initialize is only supported on Android and does not work on iOS.
    initialize: function(success, failure) {
        ble.enable(success, failure);
    },

    scan: function (number, timeout, success, failure) {
        ble.scan([UUIDS.SERVICE], timeout, success, failure);
    },

    stopScan: function (success, failure) {
        ble.stopScan(success, failure);
    },

    connect: function (device_id, success, failure) {
        var disconnect = function (device) {
            failure(device.id);
        }
        ble.connect(device_id, success, disconnect);
    },

    disconnect: function (device_id, success, failure) {
        ble.disconnect(device_id, success, failure);
    },

    /* Function isConnected calls the success callback when the peripheral is connected and the failure callback when not connected. */
    isConnected: function (device_id, success, failure) {
        ble.isConnected(device_id, success, failure);
    },

    readRSSI: function(device_id, success, failure) {
        ble.readRSSI(device_id, success, failure);
    },

    subscribe: function (device_id, success, failure) {
        ble.startNotification(device_id, UUIDS.SERVICE, UUIDS.NOTIFY, success, failure);
    },

    unsubscribe: function (device_id, success, failure) {
        ble.stopNotification(device_id, UUIDS.SERVICE, UUIDS.NOTIFY, success, failure);
    },

    read: function(device_id, service_uuid, characteristic_uuid, success, failure) {
        ble.read(device_id, service_uuid, characteristic_uuid, success, failure);
    },

// value must be an Unit8Array
    sendCommand: function (device_id, data, success, failure) {
        ble.write(device_id, UUIDS.SERVICE, UUIDS.CONTROL, data.buffer, success, failure);
    },

    //单次发送数据
    sendData: function (device_id, data, success, failure) {
        ble.writeWithoutResponse(device_id, UUIDS.SERVICE, UUIDS.DATA, data.buffer, success, failure);
    },

    requestCubes(count, period, success, failure, characteristicChanged, connected) {
        connectTask.start(this, count, period, success, failure, characteristicChanged, connected);
    },

    readFile: function (path, success, failure) {
        var fm = new FileManager();
        var readEnd = function(result) {
            success(path, result);
        };
        fm.readFile(path, readEnd, failure);
    }

};
},{"../../cordova/plugins/cordova-plugin-ble-central/www/ble":1,"../DEFAULT":4,"./FileManager_mobile":12,"./connectTask_mobile":14}],14:[function(require,module,exports){

var Cube = require('../Cube');

var _cmd;
var _changed;
var _failure;
var _success;
var _period;
var _connected;
var _foundDevices = {};
const _connectedCubes = [];
var _count;
var _timer;

module.exports = {
    start: function (cmd, count, period, success, failure, characteristicChanged, connected) {
        _cmd = cmd;
        _period = period;
        _failure = failure;
        _changed = characteristicChanged;
        _count = count;
        _success = success;
        _connected = connected;
        if (_connectedCubes.length >= count) {
            complete();
        } else {
            startScan();
        }
    },
    foundDevices: function () {
        return _foundDevices;
    },
    connectedCubes: function () {
        return _connectedCubes;
    }
};

function complete() {
    clearTimeout(_timer);
    _cmd.stopScan();
    if (_success) {
        _success(_connectedCubes);
        _success = null;
    }
}

function startScan() {
    var success = function(device) {
        _foundDevices[device.id] = device;
        connect(device.id);
    };
    _cmd.scan(_count, _period, success, _failure);
    _timer = setTimeout(function () {
        complete();
    }, _period);
}

function connect(deviceId) {
    var success = function() {
        communicate(deviceId);
    };
    _cmd.connect(deviceId, success, _failure);
}

function deviceFormat(device) {
    return {
        "deviceId" : device.id,
        "deviceName" : device.name,
        "rssi" : device.rssi
    }
}

function stateFormat(data) {
    return {
        "width" : data[8],
        "height" : data[9],
        "sideState" : data[10]
    }
}

function communicate(deviceId) {
    var onChanged = function(buffer) {
        var data = new Uint8Array(buffer);
        if (data[0] == 0xb6 && data[1] == 0x14) {
            var device = _foundDevices[deviceId];
            var cube = new Cube(deviceFormat(device), stateFormat(data));
            if (_connected) {
                _connected(cube);
            }
            if (_count > 0) {
                if (_connectedCubes.length >= _count) {
                    _cmd.disconnect(cube.deviceId);
                } else {
                    _connectedCubes.push(cube);
                    if (_connectedCubes.length == _count) {
                        complete();
                    }
                }
            }
        } else {
            _changed(deviceId, data);
        }
    };
    var data = new Uint8Array([0xa7,0xef,0xef]);
    _cmd.sendCommand(deviceId, data, null, _failure);
    _cmd.subscribe(deviceId, onChanged, _failure);
}

},{"../Cube":3}],15:[function(require,module,exports){
var xm = require('../xcaseManager');
xm.cmd = require('./command_mobile');

window.xm = xm;

},{"../xcaseManager":18,"./command_mobile":13}],16:[function(require,module,exports){
/**
 * Created by simon on 13/1/17.
 */

var ImageTask = require('./ImageTask');
var util = require('./util');
var _cmd;
var _taskTime;
var _taskCounter = {};
var _imageTasks = {};

function sendCubeMedia(cube, media, cache, success, failure) {
    var startTask = function () {
        var task = _imageTasks[cube.deviceId];
        if (!task) {
            task = new ImageTask(_cmd, cube);
            _imageTasks[cube.deviceId] = task;
        }
        void 0;
        task.start(media, cache, _taskTime, success, failure);
    };

    if (media.data) {
        startTask();
        return;
    }

    if (media.path) {
        media.description = media.path;
        var readSuccess = function (path, buffer) {
            if (buffer) {
                media.data = new Uint8Array(buffer);
            }
            startTask();
        };
        var readFail = function (error) {
            startTask();
        };
        _cmd.readFile(media.path, readSuccess, readFail);
    } else if (media.text) {
        media.description = media.text + "_" + media.font;
        var wlp = new util.WLP();
        media.data = wlp.makeText(media);
        startTask();
    }
}

module.exports = {
    initialize: function (cmd) {
        _cmd = cmd;
    },

    sendCubesMedias: function (cubes, medias, cache, success, failure) {
        if (medias.length > cubes.length) {
            if (failure) {
                failure('error: medias.length > cubes.length');
            }
            return;
        }
        _taskTime = Date.now();
        var errors = [];
        var callback = function (result) {
            var count = _taskCounter[result.startTime];
            count = count ? count : 0;
            count++;
            _taskCounter[result.startTime] = count;
            void 0;
            if (result.startTime != _taskTime) {
                return;
            }
            if (result.code) {
                errors.push(result);
            }
            if (_taskCounter[_taskTime] == medias.length) {
                void 0;
                _taskCounter = {};
                _imageTasks = {};
                if (errors.length == 0) {
                    if (success) {
                        success();
                    }
                } else {
                    if (failure) {
                        failure(errors);
                    }
                }
            }
        }
        var maxLength = 0;
        for (var i = 0; i < medias.length; i++) {
            var media = medias[i];
            if (media.text) {
                maxLength = Math.max(media.text.length, maxLength);
            }
        }
        var fontSizes = [200, 120, 100, 90, 80];
        var fontSize = maxLength < fontSizes.length ? fontSizes[maxLength-1] : fontSizes[fontSizes.length - 1];
        var font = fontSize + 'px ' + "Helvetica";
        for (var i = 0; i < medias.length; i++) {
            var media = medias[i];
            var cube = cubes[i];
            if (media.text && !media.font) {
                media.font = font;
            }
            sendCubeMedia(cube, media, cache, callback, callback);
        }
    },

    continueTask: function (deviceId, data) {
        var task = _imageTasks[deviceId];
        if (task) {
            task.continue(data);
        }
    },

    reset: function () {
        _taskTime = null;
        _taskCounter = {};
        _imageTasks = {};
    },
}
},{"./ImageTask":6,"./util":17}],17:[function(require,module,exports){
/**
 * Created by Administrator on 2016/11/29.
 */

var colorUtil = {

    rgb888to565: function (hexValue) {
        if (arguments.length == 1) {
            return (((hexValue >> 19) & 0x1f) << 11) | (((hexValue >> 10) & 0x3f) <<  5) | (((hexValue >>  3) & 0x1f));
        }

        var r = arguments[0];
        var g = arguments[1];
        var b = arguments[2];
        return (((r&0xF8)<<8) | ((g&0xFC)<<3) | ((b&0xF8)>>3));
    },


    hexToRgb: function (hexString) {
        var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexString);
        return result ? {
                r: parseInt(result[1], 16),
                g: parseInt(result[2], 16),
                b: parseInt(result[3], 16)
            } : null;
    },

    colourNameToHex: function (colour) {
        var colours = {"aliceblue":"#f0f8ff","antiquewhite":"#faebd7","aqua":"#00ffff","aquamarine":"#7fffd4","azure":"#f0ffff",
            "beige":"#f5f5dc","bisque":"#ffe4c4","black":"#000000","blanchedalmond":"#ffebcd","blue":"#0000ff","blueviolet":"#8a2be2","brown":"#a52a2a","burlywood":"#deb887",
            "cadetblue":"#5f9ea0","chartreuse":"#7fff00","chocolate":"#d2691e","coral":"#ff7f50","cornflowerblue":"#6495ed","cornsilk":"#fff8dc","crimson":"#dc143c","cyan":"#00ffff",
            "darkblue":"#00008b","darkcyan":"#008b8b","darkgoldenrod":"#b8860b","darkgray":"#a9a9a9","darkgreen":"#006400","darkkhaki":"#bdb76b","darkmagenta":"#8b008b","darkolivegreen":"#556b2f",
            "darkorange":"#ff8c00","darkorchid":"#9932cc","darkred":"#8b0000","darksalmon":"#e9967a","darkseagreen":"#8fbc8f","darkslateblue":"#483d8b","darkslategray":"#2f4f4f","darkturquoise":"#00ced1",
            "darkviolet":"#9400d3","deeppink":"#ff1493","deepskyblue":"#00bfff","dimgray":"#696969","dodgerblue":"#1e90ff",
            "firebrick":"#b22222","floralwhite":"#fffaf0","forestgreen":"#228b22","fuchsia":"#ff00ff",
            "gainsboro":"#dcdcdc","ghostwhite":"#f8f8ff","gold":"#ffd700","goldenrod":"#daa520","gray":"#808080","green":"#008000","greenyellow":"#adff2f",
            "honeydew":"#f0fff0","hotpink":"#ff69b4",
            "indianred ":"#cd5c5c","indigo":"#4b0082","ivory":"#fffff0","khaki":"#f0e68c",
            "lavender":"#e6e6fa","lavenderblush":"#fff0f5","lawngreen":"#7cfc00","lemonchiffon":"#fffacd","lightblue":"#add8e6","lightcoral":"#f08080","lightcyan":"#e0ffff","lightgoldenrodyellow":"#fafad2",
            "lightgrey":"#d3d3d3","lightgreen":"#90ee90","lightpink":"#ffb6c1","lightsalmon":"#ffa07a","lightseagreen":"#20b2aa","lightskyblue":"#87cefa","lightslategray":"#778899","lightsteelblue":"#b0c4de",
            "lightyellow":"#ffffe0","lime":"#00ff00","limegreen":"#32cd32","linen":"#faf0e6",
            "magenta":"#ff00ff","maroon":"#800000","mediumaquamarine":"#66cdaa","mediumblue":"#0000cd","mediumorchid":"#ba55d3","mediumpurple":"#9370d8","mediumseagreen":"#3cb371","mediumslateblue":"#7b68ee",
            "mediumspringgreen":"#00fa9a","mediumturquoise":"#48d1cc","mediumvioletred":"#c71585","midnightblue":"#191970","mintcream":"#f5fffa","mistyrose":"#ffe4e1","moccasin":"#ffe4b5",
            "navajowhite":"#ffdead","navy":"#000080",
            "oldlace":"#fdf5e6","olive":"#808000","olivedrab":"#6b8e23","orange":"#ffa500","orangered":"#ff4500","orchid":"#da70d6",
            "palegoldenrod":"#eee8aa","palegreen":"#98fb98","paleturquoise":"#afeeee","palevioletred":"#d87093","papayawhip":"#ffefd5","peachpuff":"#ffdab9","peru":"#cd853f","pink":"#ffc0cb","plum":"#dda0dd","powderblue":"#b0e0e6","purple":"#800080",
            "rebeccapurple":"#663399","red":"#ff0000","rosybrown":"#bc8f8f","royalblue":"#4169e1",
            "saddlebrown":"#8b4513","salmon":"#fa8072","sandybrown":"#f4a460","seagreen":"#2e8b57","seashell":"#fff5ee","sienna":"#a0522d","silver":"#c0c0c0","skyblue":"#87ceeb","slateblue":"#6a5acd","slategray":"#708090","snow":"#fffafa","springgreen":"#00ff7f","steelblue":"#4682b4",
            "tan":"#d2b48c","teal":"#008080","thistle":"#d8bfd8","tomato":"#ff6347","turquoise":"#40e0d0",
            "violet":"#ee82ee",
            "wheat":"#f5deb3","white":"#ffffff","whitesmoke":"#f5f5f5",
            "yellow":"#ffff00","yellowgreen":"#9acd32"};

        if (typeof colours[colour.toLowerCase()] != 'undefined')
            return colours[colour.toLowerCase()];


        return false;
    },

    formatColor: function (hexOrName, wansValue) {
        if (typeof hexOrName === 'string' || hexOrName instanceof String) {
            if (!hexOrName.startsWith('0x') && !hexOrName.startsWith('#')) {
                hexOrName = colorUtil.colourNameToHex(hexOrName);
            }
            if (wansValue) {
                hexOrName = hexOrName.replace('#','0x');
                hexOrName = parseInt(hexOrName, 16);
            } else {
                hexOrName = hexOrName.replace('0x','#');
            }
        } else {
            if (!wansValue) {
                hexOrName = '#' + hexOrName;
            }
        }
        return hexOrName;
    }
};

var formateUtil = {
    stringToHex: function (str) {
        var val="";
        for(var i = 0; i < str.length; i++){

            if(val == "") {
                val = str[i].toString(16).toUpperCase();
            }else{
                val += " " + str[i].toString(16).toUpperCase();
            }
        }
        return val;
    },

    arrayToHexStr: function (array) {
        var ret = '';
        array.forEach(function (a) {

            ret += a.toString(16).toUpperCase();
            ret += ' ';
        })
        return ret;
    }
};

// var html2canvas = require('./html2canvas');
var WLP = function () {
    this.makeText = function (textMedia, finish) {
        // console.log('...makeText Start...--' + Date.now());
        var size = {width:240, height:240};
        // var elem =document.createElement("input");

        /*
        var elem = document.createElement("p");
        elem.setAttribute("style", "color:red; font-size:80px");
        // elem.setAttribute("style", "");
        elem.innerHTML = "This is a test";
        document.body.appendChild(elem);
        // var elem = document.getElementById('teamButton');
        html2canvas(elem,{
            onrendered:function(canvas){
                document.body.appendChild(canvas);
                var ctx = canvas.getContext("2d");
                var imageData = ctx.getImageData(0, 0, 240, 240);
                var data = analyseImageData(imageData);
                var encoded = lzwEncode(data.indexes, size);
                var wlp = createWLP(data.colorTable, encoded, size);
                finish(wlp);
            }
        });
*/

        var imageData = drawText(textMedia, size);
        var colors = [textMedia.backgroundColor, textMedia.textColor];
        for (var i=0; i<colors.length; i++) {
            colors[i] = colorUtil.formatColor(colors[i], false);
        }
        var data = analyseImageData(imageData, colors);
        var encoded = lzwEncode(data.indexes, size);
        var wlpData = makeWlpData(data.colorTable, encoded, size);
        // console.log('...makeText End...--' + Date.now());
        return wlpData;
    };

    function drawText(textMedia, size) {
        var text = textMedia.text;
        var font = textMedia.font;
        var bgColor = colorUtil.formatColor(textMedia.backgroundColor, false);
        var textColor = colorUtil.formatColor(textMedia.textColor, false);

        var canvas = document.createElement('canvas');
        canvas.width = size.width;
        canvas.height = size.height;
        var ctx = canvas.getContext("2d");
        ctx.fillStyle = bgColor ? bgColor : "white";
        ctx.fillRect(0, 0, size.width, size.height);
        ctx.fillStyle = textColor ? textColor : "black";
        ctx.font = font ? font : "90px 黑体";
        ctx.textAlign = "center";
        ctx.textBaseline = "middle";

        var lines = [text];
        var strings = text.split(" ");
        if (text.length > 10 && strings.length > 1) {
            lines = strings;
        }
        var height = 240/(lines.length + 1);
        for (var i=0; i<lines.length; i++) {
            var y = (i+1) * height;
            var text = lines[i];
            ctx.fillText(text,120,y,220);
        }
        var data = ctx.getImageData(0, 0, size.width, size.height);

        return data;
    }

    function analyseImageData (imageData, colors) {
        var pix = imageData.data;
        var indexes = new Uint8Array(240*240*2);
        var colorTable = [];
        var index = 0;
        var bColor;
        for (var i=0; i<colors.length; i++) {
            var color = colors[i];
            if (i == 0) {
                bColor = colorUtil.hexToRgb(color);
            }
            var colorValue = colorUtil.formatColor(color, true);
            colorValue = colorUtil.rgb888to565(colorValue);
            colorTable.push(((colorValue & 0xff) << 8) | ((colorValue & 0xff00) >> 8));
        }


        for (var i = 0, n = pix.byteLength; i < n; i += 4) {
            var colorIndex = 1;
            if (bColor.r == pix[i] && bColor.g == pix[i+1] && bColor.b == pix[i+2]) {
                colorIndex = 0;
            }
            indexes[index] = colorIndex;
            index++;
        }
        return {
            colorTable : colorTable,
            indexes : indexes
        };
    }
    /*
    const OFFSET_MAX = 100;
    function analyseImageData (imageData, textColor, bgColor) {
        var pix = imageData.data;
        var colorMap = {};	//key——颜色值		value——计数索引
        var colorRGBs = [];
        var indexes = new Uint8Array(240*240*2);
        var colorTable = [];
        var index = 0;
        for (var i = 0, n = pix.byteLength; i < n; i += 4) {
            var color = colorUtil.rgb888to565(pix[i], pix[i + 1], pix[i + 2]);
            var colorIndex = colorMap[color];
            if (colorIndex == null) {
                for (var j=0; j<colorRGBs.length; j++) {
                    var colorRGB = colorRGBs[j];
                    var offset = Math.abs(colorRGB[0]-pix[i]) + Math.abs(colorRGB[1]-pix[i+1]) + Math.abs(colorRGB[2]-pix[i+2]);
                    if (offset < OFFSET_MAX) {
                        colorIndex = j;
                        break;
                    }
                }

                // var cData = ((color & 0xff) << 8) | ((color & 0xff00) >> 8);
                // for (var j=0; j<colorTable.length; j++) {
                //     var cData1 = colorTable[j];
                //     if (Math.abs(cData - cData1) < OFFSET_MAX) {
                //         colorIndex = j;
                //         break;
                //     }
                // }

                if (colorIndex == null) {
                    colorTable.push(((color & 0xff) << 8) | ((color & 0xff00) >> 8));
                    colorIndex = colorTable.length - 1;
                    colorMap[color] = colorIndex;
                    colorRGBs.push([pix[i], pix[i + 1], pix[i + 2]]);
                }
            }
            indexes[index] = colorIndex;
            index++;
        }
        console.log(colorRGBs);
        return {
            colorTable : colorTable,
            indexes : indexes
        };
    }
    */

    function lzwEncode (buf, size) {
        var max = 0;
        var table = [];
        var tableCount = 0;

        var size_in = size.width * size.height;
        const BITS = 8;
        var outsz = 0;
        var outbyte = 0;
        var outbits = 0;
        var outBuf = new Uint8Array(size_in * 2);

        var outputCode = function(crntCode, crntBits, outBuf) {
            outbyte |= (crntCode << outbits);
            outbits += crntBits;
            while (outbits >= 8) {
                outBuf[outsz++] = (outbyte & 0xff);
                outbyte >>= 8;
                outbits -= 8;
            }
        }

        var sign = new Uint8Array(256);
        for (var i = 0; i < size_in; ++i) {
            if (sign[buf[i]] == 0) {
                max ++ ;
                sign[buf[i]] = 1;
            }
        }
        max--;
        var bits = 0;
        while (max > 0) {
            bits ++ ;
            max >>= 1;
        }
        if (bits < 2) {
            bits = 2;
        }
        max = 1 << bits;
        var CLEAR_CODE = max;
        var EOF_CODE = max + 1;
        var crntBits = bits + 1;

        var crntCode = buf[0];
        for (var i = 1; i < size_in; ++i) {
            var v = buf[i];
            var k = (crntCode << 8) + v;
            var code = -1;
            for (var j = 0; j < tableCount; ++j) {
                if (table[j] == k) {
                    code = j;
                    break;
                }
            }
            if (code >= 0) {
                crntCode = code + EOF_CODE + 1;
                continue;
            }
            outputCode(crntCode, crntBits, outBuf);
            if (tableCount + EOF_CODE >= (1 << crntBits) - 1 && crntBits < BITS) {
                crntBits ++ ;
            }
            if (tableCount + EOF_CODE >= (1 << BITS) - 1) {
                outputCode(CLEAR_CODE, crntBits, outBuf);
                crntBits = bits + 1;
                tableCount = 0;
            } else {
                table[tableCount ++ ] = k;
            }
            crntCode = v;
        }
        outputCode(crntCode, crntBits, outBuf);
        outputCode(EOF_CODE, crntBits, outBuf);
        if (outbits > 0) {
            outBuf[outsz++] = (outbyte&0xff);
        }
        var data = outBuf.subarray(0, outsz);
        return data;
    }

    function makeWlpData (colorTable, encode, size) {
        var headByte = 11;
        var version = 1;
        var colorCount = Object.keys(colorTable).length;
        var enbufsize = encode.length;
        var wlp = new Uint8Array(headByte + colorCount * 2 + enbufsize);
        wlp[0] = 'W'.charCodeAt(0);
        wlp[1] = 'L'.charCodeAt(0);
        wlp[2] = 'P'.charCodeAt(0);
        wlp[3] = 11;        //Head len
        wlp[4] = (version&0xff);
        wlp[5] = ((version >> 8) & 0xff);
        wlp[6] = (size.width & 0xff);
        wlp[7] = (size.height & 0xff);
        wlp[8] = colorCount;
        wlp[9] = (enbufsize & 0xff);
        wlp[10] = ((enbufsize >> 8) & 0xff);
        var colorData = new Uint8Array(colorCount * 2);
        var j = 0;
        for(var i=0; i<colorCount;i++){
            colorData[j] = colorTable[i] & 0xff;
            colorData[j+1] = ((colorTable[i]>>8)&0xff);
            j += 2;
        }
        wlp.set(colorData, headByte);
        wlp.set(encode, headByte + colorCount*2);
        return wlp;
    }
}


module.exports.color = colorUtil;
module.exports.formate = formateUtil;
module.exports.WLP = WLP;

},{}],18:[function(require,module,exports){
/**
 * Created by simon on 10/21/16.
 */
'use strict';

var groupManager = require('./group/groupManager');
var GM = require('./group/GroupMatrix');
var combineUtil = require('./group/combineUtil');
var util = require('./util');
var Default = require('./DEFAULT');
var taskManager = require('./taskManager');
var DataFragment = require('./DataFragment');

var _onTurn;
var _onShake;
var _onDisconnect;
var _onUSBDisconnected;
var _onBatteryStateChanged;
var _onQueryPost;

var _badgeEnable = true;
var _cmd;
var _cubes;
var _cubeDict = {};
var needCount = 0;
var _cubeIndexes = [];

function ua2text(ua) {
    var h = '';
    for (var i = 0; i < ua.length; i++) {
        h += "\\0x" + ua[i].toString(16);
    }
    return h;
}

function batteryAction(cube, data) {
    if (_onBatteryStateChanged) {
        _onBatteryStateChanged(cube, data[1]);
    }
}

function shakeAction(cube, data) {
    var shakeNum = (data[2] | data[3]<<8);
    // shakeNum = Math.ceil(shakeNum/50);
    if(_onShake != null) {
        _onShake(cube, shakeNum);
    }
}

function turnAction(cube, data) {
    var lastOrien = data[2];
    var currentOrien = data[3];
    cube.orientation = currentOrien;
    if (_onTurn != null){
        _onTurn(cube, lastOrien, currentOrien);
    }
}

function queryPostAction(cube, data) {
    var currentPost = data[11];
    cube.orientation = currentPost;
    if(_onQueryPost != null){
        _onQueryPost(cube, currentPost);
    }
}

function removeCube(cube) {
    if(cube != null){
        var index = _cubes.indexOf(cube);
        if (index > -1) {
            _cubes.splice(index, 1);
        }
        _cubeDict[cube.deviceId] = null;
    }
}

function resetData() {
    _cubes && _cubes.splice(0, _cubes.length);
    _cubeDict = {};
    needCount = 0;
    // _cubeIndexes = [];
    taskManager.reset();
}

function characteristicChanged(deviceId, data) {
    var cube = _cubeDict[deviceId];
    if (cube == null) return;

    void 0;

    if (data[0] == 0xb6) {
        if(data[1] == 0x14) {
            queryPostAction(cube, data);
        } else {
            taskManager.continueTask(deviceId, data);
        }
    } else if (data[0] == 0xca) {
        if (data[1] == 0xc5) {
            groupManager.handleCubeSideStateChanged(cube, data);
        } else if (data[1] == 0xc6) {
            shakeAction(cube, data);
        } else if (data[1] == 0xc7) {
            turnAction(cube, data);
        }
    } else if (data[0] == 0xa0) {
        batteryAction(cube, data);
    }
}

function swapDisconnectedIndexes() {
    if (_cubes.length == needCount) {
        var length = Math.min(_cubes.length, _cubeIndexes.length);
        for (var i=0; i<length; i++) {
            var deviceName = _cubeIndexes[i];
            for (var j=0; j<_cubes.length; j++) {
                var cube = _cubes[j];
                if (cube.deviceName == deviceName) {
                    _cubes[j] = _cubes[i];
                    _cubes[i] = cube;
                }
            }
        }
        _cubeIndexes = [];
        for (var j=0; j<_cubes.length; j++) {
            var cube = _cubes[j];
            _cubeIndexes[j] = cube.deviceName;
        }
    }
}
// PC上USB设备被拔出时
function usbFaultDisconnected() {
    if(_onUSBDisconnected){
        _onUSBDisconnected();
    }
    resetData();
}


var xcaseManager = {
    Rotate: GM.Rotate,
    LinearType: GM.LinearType,
    Orientation: Default.Orientation,
    BatteryState: Default.BatteryState,

    printGroup: function (group) {
        var groups = group ? [group] : this.getGroups();
        for (var i = 0; i < groups.length; i++) {
            var group = groups[i];
            void 0;
            for (var j = 0; j < group.length; j++) {
                var cube = group[j];
                void 0;
                // console.log(cube.deviceName + " " + cube.media.description + " " + JSON.stringify(cube.point) + " " + cube.rotate);
            }
        }
    },

    appPlatform: function () {
        if (typeof cordova === 'object') {
            return cordova['platformId'];
        }
        return "windows";
    },


    refreshBatteryState: function (success) {
        if (!_cubes || _cubes.length == 0) return;
        var counter = _cubes.length;
        for (var i=0; i<_cubes.length; i++) {
            var cube = _cubes[i];
            var finish = (function (cube){
                return function (buffer) {
                    counter--;
                    if (buffer instanceof ArrayBuffer) {
                        var a = new Uint8Array(buffer);
                        cube.batteryLevel = a[0];
                    }
                    if (counter == 0) {
                        if (success) {
                            success();
                        }
                    }
                }
            })(cube);
            _cmd.read(cube.deviceId, Default.Battery.SERVICE, Default.Battery.LEVEL, finish, finish);
        }
    },

    //success callback is not for iOS
    initialize: function (success, failure) {
        _cmd = this.cmd;
        taskManager.initialize(_cmd);
        var interval = 30;
        var maxTimes = 6;
        if (this.appPlatform() === "ios") {
            success();
        } else if (this.appPlatform() === "android") {
            _cmd.initialize(success, failure);
        } else {
            _cmd.initialize(success, failure);
            interval = 20;
            maxTimes = 4;
        }
        DataFragment.setSendingConfig(_cmd, interval, maxTimes);
    },

    requestCubes: function (count, success, connected) {
        needCount = count;
        var onDisconnect = function (deviceId) {
            var cube = _cubeDict[deviceId];
            removeCube(cube);
            if (_onDisconnect) {
                _onDisconnect(cube);
            }
        };
        var temp = this;
        var finish = function (cubes) {
            _cubes = cubes;
            swapDisconnectedIndexes();
            temp.printGroup();
            if (success) {
                success(_cubes);
            }
            for (var i = 0; i < _cubes.length; i++) {
                var cube = _cubes[i];
                _cubeDict[cube.deviceId] = cube;
                _cmd.isConnected(cube.deviceId, null, onDisconnect);
            }
            temp.enableSideBadge();
        };
        _cmd.requestCubes(count, Default.ConnectConfig.PERIOD, finish, onDisconnect, characteristicChanged, connected);
    },

    getCubes: function () {
        return _cubes;
    },

    getTeam: function (teamId) {
        var team = _cubes.filter(function (cube) {
            return cube.teamId == teamId;
        });
        return team;
    },

    getGroups: function () {
        var list = [];
        for (var i = 0; i < _cubes.length; i++) {
            var cube = _cubes[i];
            if (list.indexOf(cube.group) < 0) {
                list.push(cube.group);
            }
        }
        return list;
    },

//  {text : 'HelloWorld', backgroundColor: 'white', textColor: '0xff0000'}, {path : 'file:///android_asset/www/img/1.wlp'},
    sendCubesMedias: function (cubes, medias, cache, success, failure) {
        taskManager.sendCubesMedias(cubes, medias, cache, success, failure);
    },

    drawCubeFrame: function (cube, frameColor, framePix = 10) {
        if (cube) {
            frameColor = util.color.formatColor(frameColor, true);
            var m565Color = util.color.rgb888to565(frameColor);
            var frameCmd = new Uint8Array([0xA5, 0x03, (m565Color >> 8) & 0xFF, m565Color & 0xFF, framePix & 0xFF]);
            _cmd.sendCommand(cube.deviceId, frameCmd);
        }
    },

    twinkleCube: function (cube, twinkleNum) {
        if (cube) {
            var data = new Uint8Array([0xA5, 0x04, twinkleNum]);
            _cmd.sendCommand(cube.deviceId, data);
        }
    },

    setCubeBackground: function (cube, bgColor) {
        if(cube){
            bgColor = util.color.formatColor(bgColor, true);
            var m565Color = util.color.rgb888to565(bgColor);
            var bcolor = new Uint8Array([0xA5, 0x01, (m565Color >> 8) & 0xFF, m565Color & 0xFF]);
            _cmd.sendCommand(cube.deviceId, bcolor);
            cube.cacheMedia = null;
            cube.media = null;
        }
    },

    createMatrix: function (medias, orientations, linearType) {
        var matrix = new GM.GroupMatrix(medias, orientations, linearType);
        return matrix;
    },

    groupCompareMatrix: function (group, matrix) {
        return groupManager.compereMatrix(group, matrix);
    },

    splitCubesAsTeams: function (teams) {
        var setCubesTeam = function (cubes, teamId) {
            for (var j = 0; j < cubes.length; j++) {
                var cube = cubes[j];
                cube.teamId = teamId;
            }
        }
        if (teams == null) {
            setCubesTeam(_cubes, null);
        } else {
            for (var i = 0; i < teams.length; i++) {
                var cubes = teams[i];
                setCubesTeam(cubes, i);
            }
        }
    },
    destroyTeams: function () {
        this.splitCubesAsTeams(null);
    },

    close: function (cube) {
        if(cube){
            _cmd.disconnect(cube.deviceId);
            removeCube(cube);
        }
    },
    closeCubes: function (cubes) {
        cubes = [].concat(cubes);
        for (var i = 0; i < cubes.length; i++) {
            var cube = cubes[i];
            _cmd.disconnect(cube.deviceId);
            removeCube(cube);
        }
    },

    showPic: function (cube, info = 1) {
        if(cube) {
            var data = new Uint8Array([0xA5, 0x05, info]);    //1--logo 2--connected indicate
            _cmd.sendCommand(cube.deviceId, data);
            cube.cacheMedia = null;
            cube.media = null;
        }
    },

    showDynamicBoarder: function (cube, cnt=4) {
        if(cube) {
            var data = new Uint8Array([0xA5, 0x06, cnt]);
            _cmd.sendCommand(cube.deviceId, data);
        }
    },

    enableSideBadge: function (enable) {
        if (_badgeEnable != enable) {
            _badgeEnable = enable;
            var enableData = _badgeEnable ? 0x02 : 0x03;
            for (var i=0; i<_cubes.length; i++) {
                var cube = _cubes[i];
                var data = new Uint8Array([0xA6,0x05,enableData]);
                _cmd.sendCommand(cube.deviceId, data);
            }
        }
    },

    registerOnTurn: function (onChanged) {
        _onTurn = onChanged;
        // cube, fromOrientation, toOrientation
    },

    registerOnShake: function (onChanged) {
        _onShake = onChanged;
        // onChanged(cube, 2);
        // cube, times
    },

    registerOnMerge: function (onChanged) {
        groupManager.registerMerge(onChanged);
    },

    registerOnDivide: function (onChanged) {
        groupManager.registerDivide(onChanged);
    },

    registerBatteryStateChanged: function (onChanged) {
        _onBatteryStateChanged = onChanged;
    },


    registerOnDisconnect: function (disconnected) {
        _onDisconnect = disconnected;
    },

    registerOnUSBDisconnect: function (onUSBDisconnected) {
        _onUSBDisconnected = onUSBDisconnected;
        _cmd.registUSBDisconnect(usbFaultDisconnected);
    },

    registerOnQueryPost: function (onQueryPost) {
        _onQueryPost = onQueryPost;
    },
    /**
     * 小块关机
     */
    powerOff: function (cube) {
        if(cube) {
            var data = new Uint8Array([0xA6, 0x05, 0x05]);  //reset [0xA6, 0x05, 0x04]
            _cmd.sendCommand(cube.deviceId, data);
        }
    },

    queryCubePost: function (cube) {
        if(cube) {
            var data = new Uint8Array([0xA6, 0x04, 0x01]);
            _cmd.sendCommand(cube.deviceId, data);
        }

    },

    /******************************************************
     *
     * 以下API为PC主机使用
     *
     ******************************************************/
    /**
     * 复位所有主机
     */
    reset: function () {
        _cmd && _cmd.resetAllCentrals();
        resetData();
    },
    /**
     * 关闭主机
     */
    closeCentrals: function () {
        _cmd.closeCentrals();
    },
    /**
     * 测试模式通过
     * @param cube
     */
    setPass: function (cube) {
        if(cube){
            var data = new Uint8Array([0xA6, 0x05, 0x01]);
            _cmd.sendCommand(cube.deviceId, data);
        }
    },
    /**
     * 开启RSSI事件
     * @param cube
     * @param threadhold
     * @param count
     */
    setRssiChangedOn: function (cube, threadhold, count) {
        cube && _cmd.setRssiOnOrOff(cube.deviceId, 1, threadhold, count);
    },
    /**
     * 关闭RSSI事件
     * @param cube
     */
    setRssiChanedOff: function (cube) {
        cube && _cmd.setRssiOnOrOff(cube.deviceId, 0);
    },
    /**
     * 注册RSSI变化事件
     * @param callback
     */
    registRssiChanged: function (callback) {
        _cmd.registRssiChanged(callback);
    }

}

module.exports = xcaseManager;

},{"./DEFAULT":4,"./DataFragment":5,"./group/GroupMatrix":8,"./group/combineUtil":10,"./group/groupManager":11,"./taskManager":16,"./util":17}]},{},[15]);
